package net.borlis.sample.web.soap.executors.common;

import net.borlis.sample.web.context.SoapHomer;
import net.borlis.sample.web.context.SoapService;
import net.borlis.sample.web.context.SoapWeldWebContext;
import net.borlis.sample.web.context.WeldWebContext;
import net.borlis.errors.annotations.TranslatedExceptionRegister;
import net.borlis.errors.exceptions.TranslatedException;
import net.borlis.gen.ws.soap.*;
import net.borlis.log.SimpleLogger;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;

import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import java.math.BigInteger;
import java.util.Date;
import java.util.logging.Logger;

/**
 * @author alex@borlis.net
 */
@Dependent
public abstract class SoapCallExecutor<Request extends SecureRequestType, Response extends ThrowableResponseType>
                            implements SoapHomer<Request,Response> {

//    private static final Logger LOGGER = Logger.getLogger(SoapCallExecutor.class.getName());

    @Inject
    private Logger logger;

    @PostConstruct
    protected void init(){
        logger.info("main context state = " + getContext().isInit());
    }

    @Inject
    private SoapWeldWebContext context;

//    @Override
    public WeldWebContext getContext() {
        return context;
    }

//    public abstract WeldWebContext getContext();

    protected abstract void execute(Request request, Response response) /* throws TranslatedException */;

    protected abstract Response prepareResponse();

    @SimpleLogger @TranslatedExceptionRegister
    public Response sendRequest(Request request) {
        Response response = prepareResponse();
        Long start = System.currentTimeMillis();
        try {
            logger.info(String.format(SoapService.REQUEST_LOG_PATTERN, this.getClass().getSimpleName(), logRequestMessage(request)));
            getContext().verifyClientKey(request.getClientAppKey(), request.getRQMetadata().getLanguage().value());
            // the main method
            execute(request, response);
            // -=-=-=-=-=-=-=-
            // usually the exception from the service
        } catch (TranslatedException e) {
            fillErrorResponse(request, response, e);
            // other exceptions - usually the soap packets issues
        } catch (Exception e) {
            try {
                throw getContext().generateException(request.getRQMetadata().getLanguage().value(), "1000", e);
            } catch (TranslatedException te) {
                fillErrorResponse(request, response, te);
            }
        }
        Long finish = System.currentTimeMillis();
        response.setVersion(request.getVersion());
        // -=-=-=- response metadata -=-=-=-=-
        RSMetadataType rsMetadata = new RSMetadataType();
        rsMetadata.setLanguage(request.getRQMetadata().getLanguage());
        rsMetadata.setTransactionID(request.getRQMetadata().getTransactionID());
        rsMetadata.setRequestID(request.getRQMetadata().getRequestID());
        rsMetadata.setResponseID(request.getRQMetadata().getRequestID()); // duplicate the req id?
        rsMetadata.setTimestamp(SoapUtils.translate(getContext(), request.getRQMetadata().getLanguage().value(), new Date()));
        rsMetadata.setExecutionDuration(BigInteger.valueOf(finish - start));
        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        response.setRSMetadata(rsMetadata);
        logger.info(String.format(SoapService.RESPONSE_LOG_PATTERN, this.getClass().getSimpleName(), logResponseMessage(response)));
        return response;
    }

    private void fillErrorResponse(Request request, Response response, TranslatedException e) {
        ErrorsType errorsType = new ErrorsType();
        ErrorType errorType = new ErrorType(); // find the key of the error
        ErrorCodeEnum ece = SoapUtils.translate(e.getKeyMaster().getKey());
        errorType.setErrorCode(ece);
        // -=-=-
        ErrorDetailsType details = new ErrorDetailsType();
        ErrorDetailType detail = new ErrorDetailType();
        final String codeName = "code";
        detail.setName(codeName );
        detail.setValue(e.getKeyMaster().getCode());
        details.getErrorDetail().add(detail);
        errorType.setErrorDetails(details);
        // -=-=-
        ErrorMsgType errorMsgType = new ErrorMsgType();
        errorMsgType.setLanguage(request.getRQMetadata().getLanguage()); // THE SAME REQUEST LOCALE
        errorMsgType.setValue(e.getTranslatedMessage()); // <- TRANSLATED BY US!
        errorType.setErrorMsg(errorMsgType);
        // -=-=-
        errorsType.getError().add(errorType);
        response.setErrors(errorsType);
    }


    protected String logRequestMessage(Request request) {
        return "| SOAP RQ |<=| " + new ReflectionToStringBuilder(request, new SoapLogRecursiveStyle()).toString();
    }

    protected String logResponseMessage(Response response) {
        return "| SOAP RS |=>| " + new ReflectionToStringBuilder(response, new SoapLogRecursiveStyle()).toString();
    }

}
